/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package client.gui;

import client.meta.FileSlot;
import client.network.ClientRequestDownloadFile;
import clientside.ControlClientSide;
import clientside.DataClientSide;
import com.cse.p2p.common.CommonSettings;
import com.cse.p2p.common.DicFile;
import com.cse.p2p.common.Message;
import com.cse.p2p.database.ClientDatabase;
import com.cse.p2p.localfile.LocalFile;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.sql.SQLClientInfoException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JSeparator;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.table.AbstractTableModel;

/**
 *
 * @author USER
 */
public class MainView extends JFrame {
	
	private JMenuBar mainMenuBar;
	private JMenu menuA;
	private JPanel mainToolbar;
	// toolbar buttons
	private JButton btnCreateDicFile;
	private JButton btnAddNewDownload;
	private JButton btnStartDownload;
	private JButton btnPauseDownload;
	private JButton btnStopDownload;
	private JRadioButton rdnShowAll;
	private JRadioButton rdnShowCompleted;
	private JRadioButton rdnShowDownloading;
	private JRadioButton rdnShowSeeding;
	// end toolbar buttons
	private JTextField statusBar;
	private JRadioButton limitDownEnable, limitUpEnable;
	private JTextField txtLimitDown, txtLimitUp;
	private JButton btnLimitDown, btnLimitUp;
	/**
	 * The main panel which contains the download panel and info panel
	 */
	private JSplitPane mainPanel;
	private JPanel downloadListPanel;
	private InfoPanel infoPanel;
	private JTable downloadListTable;
	private MainTableModel downloadListModel;
	private UploadView uploadWnd;
	//
	private ControlClientSide controlThread;
	private DataClientSide dataThread;
	private JButton btnShowUploadProgress;
	
	public MainView( ControlClientSide cThread, DataClientSide dThread ) {
		super( "P2P sharing program - Computer Networking" );
		
		this.controlThread = cThread;
		this.dataThread = dThread;
		this.setLayout( new BorderLayout( 2, 2 ) );
		
		mainMenuBar = new JMenuBar();
		
		menuA = new JMenu( "Menu A" );
		mainMenuBar.add( menuA );

//		this.setJMenuBar( mainMenuBar );

		// toolbar setup
		mainToolbar = new JPanel( new BorderLayout() );
		
		btnShowUploadProgress = new JButton( "Upload" );
		btnShowUploadProgress.setToolTipText( "There is no upload now" );
		btnShowUploadProgress.setEnabled( false );
		btnShowUploadProgress.addActionListener( new ActionListener() {
			
			@Override
			public void actionPerformed( ActionEvent e ) {
				if ( uploadWnd != null ) {
					uploadWnd.setVisible( true );
				}
			}
		} );
		
		JPanel toolbarButtonPnl = new JPanel( new FlowLayout( FlowLayout.LEFT ) );
		
		btnCreateDicFile = new JButton( "Create DicFile " );
		btnCreateDicFile.addActionListener( new ActionListener() {
			
			@Override
			public void actionPerformed( ActionEvent e ) {
				uploadWnd = new UploadView( btnCreateDicFile, controlThread, dataThread, btnShowUploadProgress );
				uploadWnd.pack();
				uploadWnd.setResizable( false );
				uploadWnd.setLocationRelativeTo( MainView.this );
				uploadWnd.setVisible( true );
				btnShowUploadProgress.setVisible( true );
				btnShowUploadProgress.setToolTipText( "Show your download" );
			}
		} );
		toolbarButtonPnl.add( btnCreateDicFile );
		
		btnAddNewDownload = new JButton( "New download" );
		btnAddNewDownload.addActionListener( new ActionListener() {
			
			@Override
			public void actionPerformed( ActionEvent e ) {
				addNewDownload();
			}
		} );
		toolbarButtonPnl.add( btnAddNewDownload );
		
		btnStartDownload = new JButton( "Start" );
		
		toolbarButtonPnl.add( btnStartDownload );
		
		btnPauseDownload = new JButton( "Pause" );
		
		toolbarButtonPnl.add( btnPauseDownload );
		
		btnStopDownload = new JButton( "Remove" );
		
		toolbarButtonPnl.add( btnStopDownload );
		
		JPanel toolbarDownSwitchPnl = new JPanel( new FlowLayout( FlowLayout.RIGHT ) );
//
//		rdnShowAll = new JRadioButton( "Show all" );
//		rdnShowAll.setSelected( true );
//		rdnShowDownloading = new JRadioButton( "Downloading" );
//		rdnShowSeeding = new JRadioButton( "Seeding" );
//		rdnShowCompleted = new JRadioButton( "Completed" );
//
//		ButtonGroup group = new ButtonGroup();
//		group.add( rdnShowAll );
//		group.add( rdnShowDownloading );
//		group.add( rdnShowSeeding );
//		group.add( rdnShowCompleted );
//
//		toolbarDownSwitchPnl.add( rdnShowAll );
//		toolbarDownSwitchPnl.add( rdnShowDownloading );
//		toolbarDownSwitchPnl.add( rdnShowSeeding );
//		toolbarDownSwitchPnl.add( rdnShowCompleted );

		limitUpEnable = new JRadioButton( "Upload limit" );
		limitDownEnable = new JRadioButton( "Download limit" );
		
		txtLimitUp = new JTextField( Long.toString( CommonSettings.DEFAULT_LIMIT_UP / 1000 ) );
		txtLimitUp.setColumns( 5 );
		
		txtLimitDown = new JTextField( Long.toString( CommonSettings.DEFAULT_LIMIT_DOWN / 1000 ) );
		txtLimitDown.setColumns( 5 );
		
		btnLimitUp = new JButton( "Apply" );
		btnLimitDown = new JButton( "Apply" );
		
		toolbarButtonPnl.add( limitDownEnable );
		toolbarButtonPnl.add( txtLimitDown );
		toolbarButtonPnl.add( new JLabel( "KB/s" ) );
		toolbarButtonPnl.add( btnLimitDown );
		toolbarButtonPnl.add( new JSeparator( JSeparator.VERTICAL ) );
		toolbarButtonPnl.add( limitUpEnable );
		toolbarButtonPnl.add( txtLimitUp );
		toolbarButtonPnl.add( new JLabel( "KB/s" ) );
		toolbarButtonPnl.add( btnLimitUp );
		
		limitUpEnable.addChangeListener( new ChangeListener() {
			
			@Override
			public void stateChanged( ChangeEvent e ) {
				txtLimitUp.setEnabled( ( ( JRadioButton ) e.getSource() ).isSelected() );
				btnLimitUp.setEnabled( ( ( JRadioButton ) e.getSource() ).isSelected() );
			}
		} );
		limitDownEnable.addChangeListener( new ChangeListener() {
			
			@Override
			public void stateChanged( ChangeEvent e ) {
				txtLimitDown.setEnabled( ( ( JRadioButton ) e.getSource() ).isSelected() );
				btnLimitDown.setEnabled( ( ( JRadioButton ) e.getSource() ).isSelected() );
			}
		} );
		
		limitUpEnable.setSelected( false );
		limitDownEnable.setSelected( false );
		txtLimitDown.setEnabled( false );
		txtLimitUp.setEnabled( false );
		btnLimitDown.setEnabled( false );
		btnLimitUp.setEnabled( false );
		
		toolbarDownSwitchPnl.add( btnShowUploadProgress );
		
		mainToolbar.add( toolbarButtonPnl, BorderLayout.LINE_START );
		mainToolbar.add( toolbarDownSwitchPnl, BorderLayout.LINE_END );
		
		this.add( mainToolbar, BorderLayout.PAGE_START );
		// end toolbar setup

		statusBar = new JTextField( "The program is ready" );
		statusBar.setEnabled( false );
		
		this.add( statusBar, BorderLayout.PAGE_END );
		
		downloadListPanel = new JPanel();
		downloadListPanel.setLayout( new BorderLayout() );
		downloadListPanel.setMinimumSize( new Dimension( this.getWidth(), 100 ) );
		
		downloadListModel = new MainTableModel();
		downloadListTable = new JTable( downloadListModel );
		downloadListTable.setFillsViewportHeight( true );
		
		downloadListPanel.add( downloadListTable.getTableHeader(), BorderLayout.PAGE_START );
		downloadListTable.addMouseListener( new MouseAdapter() {
			
			@Override
			public void mouseClicked( MouseEvent e ) {
				int row = downloadListTable.getSelectedRow();
				FileSlot fs = ( ( MainTableModel ) downloadListTable.getModel() ).getRowData( row );
				infoPanel.updateInfo( fs );
				limitUpEnable.setSelected( fs.getLimitUp() > 0 );
				limitDownEnable.setSelected( fs.getLimitDown() > 0 );
				txtLimitUp.setText( Long.toString( fs.getLimitUp() ) );
				txtLimitDown.setText( Long.toString( fs.getLimitDown() ) );
				
			}
		} );
		downloadListPanel.add( downloadListTable );
		
		
		infoPanel = new InfoPanel();
		
		mainPanel = new JSplitPane( JSplitPane.VERTICAL_SPLIT, downloadListPanel, infoPanel );
		mainPanel.setDividerLocation( 300 );
		
		this.getContentPane().add( mainPanel );

		// demo
		downloadListModel.insertLast( new FileSlot( 2, "FIle name", "/home/trunghieu/bin", 3467, "ready", 0.1, "" ) );

		// end demo

		btnStartDownload.addActionListener( new ActionListener() {
			
			@Override
			public void actionPerformed( ActionEvent e ) {
				int row = downloadListTable.getSelectedRow();
				if ( row < 0 ) {
					JOptionPane.showMessageDialog( mainToolbar, "Please select one file to start", "No file selected", JOptionPane.ERROR_MESSAGE );
					return;
				}
				try {
					MainTableModel model = ( MainTableModel ) downloadListTable.getModel();
					FileSlot fs = model.getRowData( row );
					if ( fs.isRunning() ) {
						return;
					}
					File file = new File( CommonSettings.DEFAULT_TEMP_FOLDER + File.separatorChar + fs.getFileID()) ;
					if (!file.exists()){
						file.mkdirs();
					}else{
						file.delete();
						file.mkdirs();
					}
					ClientRequestDownloadFile requestThread = new ClientRequestDownloadFile( fs.getDicfile(), fs.getFilePath() + File.separatorChar + fs.getFileName(), fs, dataThread );
					fs.setDownloadThread( requestThread );
					fs.getDownloadThread().start();
					fs.setStatus( "Downloading...");
					model.fireTableDataChanged();
				}
				catch ( Exception ex ) {
					System.err.println( "ERROR: Unknown:Starting file download" );
				}
			}
		} );
		
		btnPauseDownload.addActionListener( new ActionListener() {
			
			@Override
			public void actionPerformed( ActionEvent e ) {
				int row = downloadListTable.getSelectedRow();
				if ( row < 0 ) {
					JOptionPane.showMessageDialog( mainToolbar, "Please select one file to start", "No file selected", JOptionPane.ERROR_MESSAGE );
					return;
				}
				try {
					MainTableModel model = ( MainTableModel ) downloadListTable.getModel();
					FileSlot fs = ( model.getRowData( row ) );
					if ( !fs.isRunning() ) {
						JOptionPane.showMessageDialog( mainToolbar, "This file is currently paused", "Nothing to do", JOptionPane.INFORMATION_MESSAGE );
						return;
					}
					fs.getDownloadThread().requestStop();
					fs.setStatus( "Stopping..." );
					model.fireTableDataChanged();
				}
				catch ( Exception ex ) {
					System.err.println( "ERROR: Unknown: Pausing file download" );
				}
			}
		} );
		
		btnStopDownload.addActionListener( new ActionListener() {
			
			@Override
			public void actionPerformed( ActionEvent e ) {
				int row = downloadListTable.getSelectedRow();
				if ( row < 0 ) {
					JOptionPane.showMessageDialog( mainToolbar, "Please select one file to start", "No file selected", JOptionPane.ERROR_MESSAGE );
					return;
				}
				try {
					MainTableModel model = ( MainTableModel ) downloadListTable.getModel();
					FileSlot fs = ( model.getRowData( row ) );
					if ( fs.isRunning() ) {
						fs.getDownloadThread().requestStop();
					}
					model.remove( row );
					model.fireTableDataChanged();
					ClientDatabase.removeFile(fs.getFileID());
				}
				catch ( Exception ex ) {
					System.err.println( "ERROR: Unknown: Stopping file download" );
				}
			}
		} );
		
		addWindowListener( new WindowListener() {
			
			@Override
			public void windowOpened( WindowEvent e ) {
				System.out.println( "Window opened" );
				MainView.this.getSavedList();
			}
			
			@Override
			public void windowClosing( WindowEvent e ) {
				System.out.println( "Window is closing ... " );
				MainView.this.saveList();
				try {
					Socket socket = new Socket( CommonSettings.HOST_ADDRESS, CommonSettings.SERVER_SERVERSOCKET );
					PrintStream prs = new PrintStream( socket.getOutputStream() );
					prs.println( new Message( Message.Command.GET, Message.Keyword.SIGNOUT, socket.getLocalSocketAddress().toString() ) );
					prs.close();
				}
				catch ( IOException ioEx ) {
					System.err.println( "ERROR: SIGNOUT: socket error" );
					ioEx.printStackTrace();
				}
			}
			
			@Override
			public void windowClosed( WindowEvent e ) {
			}
			
			@Override
			public void windowIconified( WindowEvent e ) {
			}
			
			@Override
			public void windowDeiconified( WindowEvent e ) {
			}
			
			@Override
			public void windowActivated( WindowEvent e ) {
			}
			
			@Override
			public void windowDeactivated( WindowEvent e ) {
			}
		} );
		
		btnLimitUp.addActionListener( new ActionListener() {
			
			@Override
			public void actionPerformed( ActionEvent e ) {
				int row = downloadListTable.getSelectedRow();
				if ( row < 0 ) {
					JOptionPane.showMessageDialog( mainToolbar, "Please select one file to start", "No file selected", JOptionPane.ERROR_MESSAGE );
					return;
				}
				try {
					MainTableModel model = ( MainTableModel ) downloadListTable.getModel();
					FileSlot fs = ( model.getRowData( row ) );
					if ( fs.isRunning() ) {
						fs.setUpSpeed( Long.parseLong( txtLimitUp.getText() ) );
					}
					else {
						JOptionPane.showMessageDialog( mainToolbar, "This download is currently paused", "Nothing to do", JOptionPane.INFORMATION_MESSAGE );
					}
				}
				catch ( Exception ex ) {
					System.err.println( "ERROR: Unknown: Limit upload speed" );
				}
			}
		} );
		btnLimitDown.addActionListener( new ActionListener() {
			
			@Override
			public void actionPerformed( ActionEvent e ) {
				int row = downloadListTable.getSelectedRow();
				if ( row < 0 ) {
					JOptionPane.showMessageDialog( mainToolbar, "Please select one file to start", "No file selected", JOptionPane.ERROR_MESSAGE );
					return;
				}
				try {
					MainTableModel model = ( MainTableModel ) downloadListTable.getModel();
					FileSlot fs = ( model.getRowData( row ) );
					if ( fs.isRunning() ) {
						fs.setDownSpeed( Long.parseLong( txtLimitDown.getText() ) );
					}
					else {
						JOptionPane.showMessageDialog( mainToolbar, "This download is currently paused", "Nothing to do", JOptionPane.INFORMATION_MESSAGE );
					}
				}
				catch ( Exception ex ) {
					System.err.println( "ERROR: Unknown: Limit download speed" );
				}
			}
		} );
	}

	public void saveList() {
		MainTableModel model = ( MainTableModel ) downloadListTable.getModel();
		String path = ( new File( "." ) ).getAbsolutePath() + File.separatorChar + "session.ser";
		model.writeToFile( path );
	}
	
	public void getSavedList() {
		MainTableModel model = ( MainTableModel ) downloadListTable.getModel();
		String path = ( new File( "." ) ).getAbsolutePath() + File.separatorChar + "session.ser";
		model.readFromFile( path );
		model.fireTableDataChanged();
	}
	
	private void addNewDownload() {
		JFrame addDownloadDlg = new JFrame( "Create new download" );
		JPanel mainAddDownload = new JPanel();
		mainAddDownload.setBorder( new EmptyBorder( 6, 6, 6, 6 ) );
		addDownloadDlg.getContentPane().add( mainAddDownload );
		mainAddDownload.setLayout( new GridBagLayout() );
		GridBagConstraints c = new GridBagConstraints();
		c.ipadx = 6;
		c.ipady = 6;
		c.anchor = GridBagConstraints.LINE_START;
		
		JLabel lblSelectDicFile = new JLabel( "Choose the Dic file" );
		c.gridx = 0;
		c.gridy = 0;
		mainAddDownload.add( lblSelectDicFile, c );
		
		JTextField txtSelectDicFile = new JTextField();
		txtSelectDicFile.setPreferredSize( new Dimension( 600, 24 ) );
		c.gridx = 1;
		c.gridy = 0;
		mainAddDownload.add( txtSelectDicFile, c );
		
		JTextField txtSelectSaveFile = new JTextField();
		txtSelectSaveFile.setPreferredSize( new Dimension( 600, 24 ) );
		c.gridx = 1;
		c.gridy = 1;
		mainAddDownload.add( txtSelectSaveFile, c );
		
		JButton btnSelectDicFile = new JButton( "Browse ..." );
		c.gridx = 2;
		c.gridy = 0;
		btnSelectDicFile.addActionListener( new SelectDicFileAction( txtSelectDicFile, mainAddDownload, txtSelectSaveFile ) );
		mainAddDownload.add( btnSelectDicFile, c );
		
		JLabel lblSelectSaveFile = new JLabel( "Save your file to" );
		c.gridx = 0;
		c.gridy = 1;
		mainAddDownload.add( lblSelectSaveFile, c );
		
		
		
		JButton btnSelectSaveFile = new JButton( "Browse ..." );
		c.gridx = 2;
		c.gridy = 1;
		btnSelectSaveFile.addActionListener( new SelectSaveFileAction( txtSelectSaveFile, mainAddDownload ) );
		mainAddDownload.add( btnSelectSaveFile, c );
		
		JPanel addFooterPanel = new JPanel( new FlowLayout( FlowLayout.RIGHT ) );
		JButton btnOK = new JButton( "OK" );
		btnOK.addActionListener( new ConfirmNewDownloadAction( downloadListModel, txtSelectDicFile, txtSelectSaveFile, addDownloadDlg ) );
		addFooterPanel.add( btnOK );
		JButton btnCancel = new JButton( "Cancel" );
		btnCancel.addActionListener( new OnCloseAction( addDownloadDlg ) );
		addFooterPanel.add( btnCancel );
		c.gridx = 0;
		c.gridy = 2;
		c.gridwidth = 3;
		c.insets = new Insets( 20, 0, 0, 0 );
		c.fill = GridBagConstraints.HORIZONTAL;
		mainAddDownload.add( addFooterPanel, c );
		
		addDownloadDlg.setLocation( 20, 200 );
		addDownloadDlg.pack();
		addDownloadDlg.setVisible( true );
		
	}
	
	private class SelectDicFileAction implements ActionListener {
		
		private JTextField txtField, txtName;
		private Component parent;
		
		public SelectDicFileAction( JTextField textField, Component parent, JTextField txtName ) {
			txtField = textField;
			this.parent = parent;
			this.txtName = txtName;
		}
		
		@Override
		public void actionPerformed( ActionEvent e ) {
			JFileChooser jfc = new JFileChooser();
			jfc.setFileFilter( new javax.swing.filechooser.FileFilter() {
				
				@Override
				public boolean accept( File f ) {
					if ( f.isDirectory() ) {
						return true;
					}
					String fileName = f.getName();
					int pos = fileName.lastIndexOf( "." );
					if ( pos < 0 ) {
						return false;
					}
					return fileName.substring( pos ).equalsIgnoreCase( "." + DicFile.FILE_EXT );
				}
				
				@Override
				public String getDescription() {
					return DicFile.FILE_EXT_DESC;
				}
			} );
			jfc.setAcceptAllFileFilterUsed( false );
			jfc.setFileSelectionMode( JFileChooser.FILES_ONLY );
			int returnVal = jfc.showOpenDialog( parent );
			if ( returnVal == JFileChooser.APPROVE_OPTION ) {
				File file = jfc.getSelectedFile();
				DicFile dicFile = DicFile.parseDicFileFromXML( LocalFile.getContentDicFile( file.getAbsolutePath() ) );
				txtName.setText( file.getParent() + File.separatorChar + dicFile.getFileName() );
				txtField.setText( file.getAbsolutePath() );
			}
		}
	}
	
	private class SelectSaveFileAction implements ActionListener {
		
		private JTextField txtField;
		private Component parent;
		
		public SelectSaveFileAction( JTextField textField, Component parent ) {
			
			this.txtField = textField;
			this.parent = parent;
		}
		
		@Override
		public void actionPerformed( ActionEvent e ) {
			JFileChooser jfc = new JFileChooser( txtField.getText() );
			jfc.setFileSelectionMode( JFileChooser.FILES_ONLY );
			int returnVal = jfc.showSaveDialog( parent );
			if ( returnVal == JFileChooser.APPROVE_OPTION ) {
				File file = jfc.getSelectedFile();
				txtField.setText( file.getAbsolutePath() );
			}
		}
	}
	
	private class ConfirmNewDownloadAction implements ActionListener {
		
		private MainTableModel tblList;
		private JTextField txtDicPath, txtFilePath;
		private JFrame parent;
		
		public ConfirmNewDownloadAction( MainTableModel tblList, JTextField txtDicPath, JTextField txtFilePath, JFrame parent ) {
			this.tblList = tblList;
			this.txtDicPath = txtDicPath;
			this.txtFilePath = txtFilePath;
			this.parent = parent;
		}
		
		@Override
		public void actionPerformed( ActionEvent e ) {
			File file = new File( txtDicPath.getText() );
			try {
				DicFile dicFile = DicFile.parseDicFileFromXML( LocalFile.getContentDicFile( txtDicPath.getText() ) );
				FileSlot fslot = new FileSlot( dicFile.getFileID(), dicFile.getFileName(),
											   ( new File( txtFilePath.getText() ) ).getParent(),
											   dicFile.getFileSize(), "ready", 0.0, dicFile.getFileName(), dicFile );
				tblList.insertLast( fslot );
				tblList.fireTableDataChanged();
//				ClientDatabase.openDatabase();
				ClientDatabase.NewFile( fslot.getFileName(), fslot.getFileName() + System.currentTimeMillis(), fslot.getDicfile().getFileID(), fslot.getFileSize(), fslot.getFilePath(), "", "" );
//				ClientDatabase.closeDatabase();
				parent.setVisible( false );
				parent.dispose();
			}
//			catch ( IOException ioEx ) {
//				System.err.println( "Cannot read the file " + file.getAbsolutePath() );
//			}
			catch ( SQLException sqlEx ) {
				System.err.println( "ERROR: Database: Adding new file" );
				sqlEx.printStackTrace();
			}
			catch ( Exception ex ) {
				System.err.println( "ERROR: Unknown: Adding new file" );
				ex.printStackTrace();
			}
		}
	}
	
	private class OnCloseAction implements ActionListener {
		
		private JFrame parent;
		
		public OnCloseAction( JFrame parent ) {
			this.parent = parent;
		}
		
		@Override
		public void actionPerformed( ActionEvent e ) {
			parent.dispose();
		}
	}
	
	private static class MainTableModel extends AbstractTableModel {
		
		private String[] columnNames = { FileSlot.KEY_FILENAME, FileSlot.KEY_FILESIZE, FileSlot.KEY_STATUS,
										 FileSlot.KEY_DOWNSPD, FileSlot.KEY_DOWNLOADED, FileSlot.KEY_EST_TIME,
										 FileSlot.KEY_UPSPD, FileSlot.KEY_UPLOADED, FileSlot.KEY_UD_RATIO };
		private List<FileSlot> data = new ArrayList<FileSlot>();
		
		@Override
		public int getRowCount() {
			return data.size();
		}
		
		@Override
		public int getColumnCount() {
			return columnNames.length;
		}
		
		@Override
		public Object getValueAt( int rowIndex, int columnIndex ) {
			FileSlot item = data.get( rowIndex );
			String ret = "";
			switch ( columnIndex ) {
				case 0:
					ret = item.getFileName();
					break;
				case 1:
					ret = Long.toString( item.getFileSize() / 1024 ) + "KB";
					break;
				case 2:
					ret = item.getStatus();
					break;
				case 3:
					ret = Long.toString( item.getDownSpeed() / 1000 ) + "KB/s";
					break;
				case 4:
					ret = Long.toString( item.getDownloaded() / 1024 ) + "KB";
					break;
				case 5:
					long val = item.getEstTime();
					if ( val == Long.MAX_VALUE ) {
						ret = "N/A";
					}
					else {
						ret = Long.toString( item.getEstTime() ) + "s";
					}
					break;
				case 6:
					ret = Long.toString( item.getUpSpeed() / 1000 ) + "KB/s";
					break;
				case 7:
					ret = Long.toString( item.getUploaded() / 1024 ) + "KB";
					break;
				case 8:
					
					ret = Double.toString( item.getUpdownRatio() );
					break;
				default:
					
					break;
			}
			return ret;
		}
		
		@Override
		public String getColumnName( int col ) {
			return columnNames[col];
		}
		
		@Override
		public Class getColumnClass( int c ) {
			return getValueAt( 0, c ).getClass();
		}
		
		public void insert( int index, FileSlot obj ) {
			data.add( index, obj );
		}
		
		public void insertLast( FileSlot obj ) {
			data.add( obj );
		}
		
		public void remove( int index ) {
			data.remove( index );
		}
		
		public FileSlot getRowData( int index ) {
			if ( index < 0 || index > data.size() ) {
				return null;
			}
			else {
				return data.get( index );
			}
		}
		
		public void writeToFile( String path ) {
			try {
				File file = new File( path );
				ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream( file ) );
				oos.writeObject( data );
			}
			catch ( FileNotFoundException fnfEx ) {
				System.err.println( "ERROR: Serialization: Cannot write table data to disk, file not found" );
				fnfEx.printStackTrace();
			}
			catch ( IOException ioEx ) {
				System.err.println( "ERROR: Serialization: Cannot write table data to disk, read/write error" );
				ioEx.printStackTrace();
			}
		}
		
		public void readFromFile( String path ) {
			try {
				File file = new File( path );
				ObjectInputStream ois = new ObjectInputStream( new FileInputStream( file ) );
				data = ( ArrayList<FileSlot> ) ois.readObject();
			}
			catch ( FileNotFoundException fnfEx ) {
				System.err.println( "ERROR: Serialization: Cannot read table data from disk, file not found" );
				fnfEx.printStackTrace();
			}
			catch ( IOException ioEx ) {
				System.err.println( "ERROR: Serialization: Cannot read table data from, read/write error" );
				ioEx.printStackTrace();
			}
			catch ( ClassNotFoundException cnfEx ) {
				System.err.println( "ERROR: Serialization: Cannot read from disk, class not found" );
				cnfEx.printStackTrace();
			}
		}
	}
}
